package cn.techcave.chat.jpa.service

import cn.techcave.chat.jpa.domain.Author
import cn.techcave.chat.jpa.domain.Post
import cn.techcave.chat.jpa.repository.AuthorRepo
import cn.techcave.chat.jpa.repository.PostRepo
import com.querydsl.core.types.dsl.PathBuilder
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.domain.*
import org.springframework.data.jpa.domain.Specification
import org.springframework.data.jpa.domain.Specifications.where
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import javax.persistence.criteria.CriteriaBuilder
import javax.persistence.criteria.CriteriaQuery
import javax.persistence.criteria.Predicate
import javax.persistence.criteria.Root

@Service
class PostService {

    @Autowired
    lateinit var postRepo: PostRepo

    @Autowired
    lateinit var authorRepo: AuthorRepo

    /**
     * 演示通过QBE实现标题和内容查询
     */
    fun findByTitleOrContent(title: String, content: String): MutableList<Post>? {
        // 定义matcher,也就是匹配规则
        val matcher = ExampleMatcher.matching()
                .withIgnorePaths("author")//忽略value属性
                .withIgnoreNullValues()//忽略空值
//                .withIncludeNullValues()//包含空值
                .withMatcher("title", ExampleMatcher.GenericPropertyMatcher().contains().ignoreCase())//字段title，包含关系，忽略大小写
                .withMatcher("content", ExampleMatcher.GenericPropertyMatcher().contains().ignoreCase())//字段content，包含关系，忽略大小写

        // 匹配样本
        var exmPost = Post()
        exmPost.title = title
        val example = Example.of(exmPost, matcher)
        return postRepo.findAll(example)
    }

    /**
     * 生成标题的Specification查询
     */
    fun titleLike(title: String): Specification<Post> {
        return object : Specification<Post> {
            override fun toPredicate(root: Root<Post>, query: CriteriaQuery<*>,
                                     builder: CriteriaBuilder): Predicate {
                return builder.like(root.get("name"), "%$title%")
            }
        }
    }

    /**
     * 生成内容的Specification查询
     */
    fun contentLike(content: String): Specification<Post> {
        return object : Specification<Post> {
            override fun toPredicate(root: Root<Post>, query: CriteriaQuery<*>,
                                     builder: CriteriaBuilder): Predicate {
                return builder.like(root.get("name"), "%$content%")
            }
        }
    }

    /**
     * 根据title单一条件查询
     */
    fun findByTitle(title: String) = postRepo.findAll(titleLike(title))

    /**
     * 根据content单一条件查询
     */
    fun findByContent(content: String) = postRepo.findAll(contentLike(content))

    /**
     * title和content组合条件查询
     */
    fun findByTintLike(title: String, content: String): MutableList<Post>? {
        return postRepo.findAll(where(titleLike(title)).or(contentLike(content)))
    }

//    fun findByTitleDsl(title:String) {
//        var p:Predicate = Post().author.equals("")//PathBuilder<Post>(Post::class.java, "post").
//    }

    /**
     * 演示Sort对象排序
     */
    fun findAuthorOrderBy(): MutableList<Author>? {
        // 按修改日期降序，作者名和创建日期升序
        var sort = Sort(Sort.Direction.DESC, "updateDate").and(Sort(Sort.Direction.ASC, "name", "createDate"))
        return authorRepo.findAll(sort)
    }

    /**
     * 演示自定义分页
     */
    fun findAuthor(page: Int, size:Int, sort:Sort): Page<Author>? {
        var p = PageRequest(page, size, sort)
        return authorRepo.findAll(p)
    }

    /**
     * 从外部传入Pageable
     */
    fun findAuthor(page:Pageable?) = authorRepo.findAll(page)

    /**
     * 演示Service层事务
     */
    @Transactional
    fun newAuthorWithPost(authorName:String, title:String, content:String) {
        var author = Author()
        author.name = authorName
        authorRepo.saveAndFlush(author)
        var post = Post()
        post.title = title
        post.content = content
        post.author = author
        postRepo.saveAndFlush(post)
    }
}